package com.app.public_dependency.loader;

import com.app.public_dependency.response.Result;
import com.github.springtestdbunit.annotation.DatabaseOperation;
import com.github.springtestdbunit.operation.DatabaseOperationLookup;
import com.github.springtestdbunit.operation.DefaultDatabaseOperationLookup;
import com.zaxxer.hikari.HikariDataSource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.CompositeDataSet;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ReplacementDataSet;
import org.dbunit.dataset.excel.XlsDataSet;
import org.dbunit.ext.postgresql.PostgresqlDataTypeFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.stereotype.Repository;

import java.io.File;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zhangzy
 * @description 数据库插入和回滚加载器
 */
@Repository
@SuppressWarnings("unused")
@Slf4j
@RequiredArgsConstructor
public class DbDataLoader {

    /**
     * 数据库操作查找
     */
    private final DatabaseOperationLookup databaseOperationLookup = new DefaultDatabaseOperationLookup();

    /**
     * 上下文
     */
    private final ApplicationContext context;

    /**
     * 数据库操作
     *
     * @param operation 数据库操作类型
     * @param value     目标数据配置文件
     * @param schema    スキーマ
     */
    public Result operateDatabase(DatabaseOperation operation, String value, String schema) {
        // 数据库连接
        Connection conn = null;
        // 数据源
        HikariDataSource dataSource = null;
        try {
            // 为 Excel 创建数据集
            ReplacementDataSet replacementDataSet = new ReplacementDataSet(
                    new XlsDataSet(new File(value)));
            replacementDataSet.addReplacementObject("(NULL)", null);
            final List<IDataSet> datasets = new ArrayList<IDataSet>() {
                private static final long serialVersionUID = 1L;

                {
                    add(replacementDataSet);
                }
            };
            dataSource = (HikariDataSource) context.getBean("SecondaryDataSource");
            // 获取连接
            conn = dataSource.getConnection();
            conn.setAutoCommit(false);
            final IDatabaseConnection connection = new DatabaseConnection(conn,
                    StringUtils.isEmpty(schema) ? conn.getSchema() : schema.toUpperCase());

            // 设置 ORACLE 的 DATATYPE，以便也可以操作 Clob 类型列。
            connection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
                    new PostgresqlDataTypeFactory());
            // 设置为允许空项目
            connection.getConfig().setProperty(DatabaseConfig.FEATURE_ALLOW_EMPTY_FIELDS, true);
            org.dbunit.operation.DatabaseOperation dbUnitOperation = databaseOperationLookup.get(operation);
            final IDataSet dataSet = new CompositeDataSet(datasets.toArray(new IDataSet[datasets.size()]));
            dbUnitOperation.execute(connection, dataSet);
            conn.commit();
        } catch (Exception e) {
            log.error(e.getMessage());
            try {
                assert conn != null;
                conn.rollback();
            } catch (Exception ex) {
                log.error(ex.getMessage());
            }
            return Result.error();
        } finally {
            DataSourceUtils.releaseConnection(conn, dataSource);
        }
        return Result.success();
    }
}
